﻿using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
using System;
using System.Windows.Forms;
#if (!DEBUG)
using System.Diagnostics;
#endif
using Buffer = SharpDX.Direct3D11.Buffer;

namespace MikadoShooter
{
    public class Game : Component
    {
        private const int STRIDE = 2 * 4 * sizeof(float);   //2 * Vector4

        public Game(): base("MikadoShooter Game")
        {
            Cursor.Hide();                                  //Hide mouse
#if (DEBUG)
            Configuration.EnableObjectTracking = true;      //Tracks resources that havent not been released
#else
            Debug.Listeners.Clear();                        //Hide debug output
#endif
        }

        public void Run()
        {
            TargetAction targetAction;
            Fps fps = new Fps();
            Level level = new Level();

            //XAudio2 soundeffects
            SoundPlayer soundPlayer = ToDispose(new SoundPlayer());
            soundPlayer.InitSoundFile();

            DXWindow dXWindow = ToDispose(GameHelper.WindowInit());
            Effect effect = ToDispose(GameHelper.EffectInit(dXWindow.Device, "effect.fx"));
            dXWindow.ResizeStringTexture(effect, level);

            //Lines
            DrawBg drawBg = new DrawBg();                                                                               //Border lines
            DrawTarget drawTarget = new DrawTarget(out targetAction, level, soundPlayer);                               //Targer lines
            Buffer bufferL = ToDispose(GameHelper.GetBuffer(dXWindow.Device, (drawBg.Length + drawTarget.Length) * STRIDE));        //Create buffer for lines

            //PointList
            DrawMouse drawMouse = new DrawMouse(dXWindow);                                                               //Mouse point
            DrawShooter drawShooter = new DrawShooter(dXWindow, targetAction, drawBg.Update, level, soundPlayer);        //Shoot points
            Buffer bufferPL = ToDispose(GameHelper.GetBuffer(dXWindow.Device, (drawMouse.Length + drawShooter.Length) * STRIDE));   //Create buffer for pointlines

            //Text
            Buffer bufferText = ToDispose(GameHelper.GetTextureBuffer(dXWindow.Device));

            string gpuName = GameHelper.GetGpuName(dXWindow.SwapChain);                                                             //Get primary gpu name
            dXWindow.RenderForm.Text = string.Format("Level:{0,-10} GPU:{1,-40} FPS:{2,-20}", level.LevelNr, gpuName, fps.Draw());  //Init title text
            
            //Nagscreen
            soundPlayer.PlaySound(eSoundname.Complete);
            level.MessageBox.NewMessage("{0}{1}{2}{1}{3}", Application.ProductName, Environment.NewLine, Application.ProductVersion, "Author " + Application.CompanyName);

            RenderLoop.Run(dXWindow.RenderForm, () =>
            {
                //Update
                drawMouse.Update(dXWindow.RenderForm.Location, drawShooter.GetCurrentColor());
                drawShooter.Update(dXWindow.RenderForm.Location);

                //ReCreate buffer if needed
                if (level.MessageBox.IsNeedNewBuffer)
                    bufferL = ToDispose(GameHelper.GetBuffer(dXWindow.Device, (drawBg.Length + drawTarget.Length) * STRIDE));

                //Clear
                dXWindow.Device.ImmediateContext.ClearRenderTargetView(dXWindow.RenderView, StdColors.ClearColor);

                //Apply effect
                effect.GetTechniqueByName("Render").GetPassByIndex(0).Apply(dXWindow.Device.ImmediateContext);

                //Render points
                GameHelper.Render(dXWindow.Device, bufferPL, STRIDE, PrimitiveTopology.PointList, drawMouse, drawShooter);

                //Render lines
                GameHelper.Render(dXWindow.Device, bufferL, STRIDE, PrimitiveTopology.LineList, drawBg, drawTarget);

                //Write Text
                if (level.MessageBox.IsMessage())
                {
                    //Change effecttechnique to texture mode
                    effect.GetTechniqueByName("RenderTexture").GetPassByIndex(0).Apply(dXWindow.Device.ImmediateContext);

                    //Render Texture first run 
                    if (level.MessageBox.IsNeedRenderTexture())
                        GameHelper.EffectStringTexture(effect, dXWindow, level.MessageBox.Text);

                    //Render button
                    GameHelper.RenderBuffer(dXWindow.Device, bufferText, STRIDE);
                }

                //Present to screen
                dXWindow.SwapChain.Present(1, PresentFlags.None);

                //FPS counter
                if (fps.Update())
                    dXWindow.RenderForm.Text = string.Format("Level:{0,-10} GPU:{1,-40} FPS:{2,-20}", level.LevelNr, gpuName, fps.Draw());
            });
        }
    }
}